package tools

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"errors"
	"fmt"
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"golang.org/x/image/bmp"

	"github.com/nfnt/resize"
)

//类型检测 要检测的变量  期望变量类型
func Istype(params interface{}, t string) bool {

	//数据初始化
	var (
		return_val bool = false
	)
	v := reflect.ValueOf(params)
	//获取传递参数类型
	v_t := v.Type()

	//类型名称对比
	if v_t.String() == t {
		return_val = true
	}
	return return_val
}

//类型检测是否为手机号
func Isphone(mobile interface{}) (bool, string) {
	if Istype(mobile, "string") == false && Istype(mobile, "int") == false {
		return false, "数据格式错误，必须为string，或者int类型数据"
	}
	fmt.Print(mobile)
	// num := string(mobile.(int))
	// num := strconv.Itoa(mobile.(int))
	num, _ := Forstring(mobile.(int))
	result, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]\d{4,8})$`, num)
	if result {
		return true, ""
	} else {
		return false, "手机号格式错误"
	}
}

//md5加密
func Md5(s string) string {
	data := []byte(s)
	has := md5.Sum(data)
	md5str := fmt.Sprintf("%x", has) //将[]byte转成16进制
	return md5str
}

//转字符串
func Forstring(f interface{}) (string, interface{}) {
	str := ""
	msg := true
	switch f.(type) {
	case string:
		str = f.(string)
	case int, int16, int32, int64, int8:
		str = strconv.Itoa(f.(int))
	case float64:
		in := int(f.(float64))
		str = strconv.Itoa(in)
	case float32:
		in := int(f.(float32))
		str = strconv.Itoa(in)
	default:
		msg = false
		str = ""
	}
	return str, msg
}
func Delfile(dir string) {
	finfo, err := os.Stat(dir)
	if err != nil {
		// no such file or dir
		fmt.Print("o such file or dir")
		return
	}
	if finfo.IsDir() {
		os.RemoveAll(dir)
		// it's a file
	} else {
		os.Remove(dir)
		// it's a directory
	}
}

type Savebase64imgType struct {
	Data string
	Dir  string
	Day  time.Duration
}

//保存base64图片
func Savebase64img(other Savebase64imgType) (string, string, string) {
	savename := ""
	dst := ""
	imgtypes := ""
	idx := strings.Index(other.Data, ";base64,")
	if idx < 0 {
		panic("必须为base64格式图片")
	}
	ImageType := other.Data[11:idx]
	// log.Println(ImageType)

	unbased, _ := base64.StdEncoding.DecodeString(other.Data[idx+8:])
	reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(other.Data[idx+8:]))
	imgCfg, _, err := image.DecodeConfig(reader)
	bili := imgCfg.Width / imgCfg.Height
	if err != nil {
		panic("Cannot decode base64")
	}
	r := bytes.NewReader(unbased)
	switch ImageType {
	case "png":
		im, err := png.Decode(r)
		if err != nil {
			panic("Bad png")
		}

		f, err := os.OpenFile(other.Dir+".png", os.O_WRONLY|os.O_CREATE, 0755)
		if err != nil {
			panic("Cannot open file")
		}
		savename = other.Dir + ".png"
		imgtypes = ".png"
		png.Encode(f, im)
	case "jpeg":
		im, err := jpeg.Decode(r)
		if err != nil {
			panic("Bad jpeg")
		}

		f, err := os.OpenFile(other.Dir+".jpeg", os.O_WRONLY|os.O_CREATE, 0755)
		if err != nil {
			panic("Cannot open file")
		}
		imgtypes = ".jpeg"
		savename = other.Dir + ".jpeg"
		jpeg.Encode(f, im, nil)
	case "gif":
		im, err := gif.Decode(r)
		if err != nil {
			panic("Bad gif")
		}

		f, err := os.OpenFile(other.Dir+".gif", os.O_WRONLY|os.O_CREATE, 0755)
		if err != nil {
			panic("Cannot open file")
		}
		imgtypes = ".gif"
		savename = other.Dir + ".gif"
		gif.Encode(f, im, nil)
	}
	// if other.Small == true {
	dst = strings.Replace(savename, ".", "_small.", 1)
	Scaleimg(savename, dst, 200, 200/bili)
	return savename, dst, imgtypes
	// }
	// if other.Timeout == true {
	// 	timer := time.NewTimer(other.Day * 24 * time.Hour)
	// 	<-timer.C
	// 	Delfile(dst)
	// 	Delfile(savename)
	// }

	// src := "data/1.gif"
	// dst := strings.Replace(src, ".", "_small.", 1)
	// fmt.Println("src=", src, " dst=", dst)
	// fIn, _ := os.Open(src)
	// defer fIn.Close()

	// fOut, _ := os.Create(dst)
	// err := scale(fIn, fOut, 150, 150, 100)
}

//保存文件 base64,name
type Savebase64fileType struct {
	Data string
	Name string
}

func Savebase64file(obj Savebase64fileType) {
	reader := strings.NewReader(obj.Data)
	decoder := base64.NewDecoder(base64.StdEncoding, reader)
	// 以流式解码
	buf := make([]byte, 2)
	// 保存解码后的数据
	dst := ``
	for {
		n, err := decoder.Read(buf)
		if n == 0 || err != nil {
			break
		}
		dst += string(buf[:n])
	}
	ioutil.WriteFile(obj.Name, []byte(dst), 0755)
}

//缩略图生成 输入图片src,输出图片src，宽度，高度，精度(0~100)
func Scaleimg(insrc string, outsrx string, width, height int) error {
	fIn, _ := os.Open(insrc)
	origin, fm, err := image.Decode(fIn)
	fOut, _ := os.Create(outsrx)
	if err != nil {
		return err
	}
	if width == 0 || height == 0 {
		width = origin.Bounds().Max.X
		height = origin.Bounds().Max.Y
	}
	quality := 100
	canvas := resize.Thumbnail(uint(width), uint(height), origin, resize.Lanczos3)

	//return jpeg.Encode(out, canvas, &jpeg.Options{quality})

	switch fm {
	case "jpeg":
		return jpeg.Encode(fOut, canvas, &jpeg.Options{quality})
	case "png":
		return png.Encode(fOut, canvas)
	case "gif":
		return gif.Encode(fOut, canvas, &gif.Options{})
	case "bmp":
		return bmp.Encode(fOut, canvas)
	default:
		return errors.New("ERROR FORMAT")
	}
	// return nil
}
